using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;
using Phoenix.Filters;

namespace Phoenix.Framework
{
    internal static class ReflectedAttributeCache
    {
        private static readonly Dictionary<MethodInfo, ReadOnlyCollection<FilterAttribute>> methodFilterAttributeCache = 
            new Dictionary<MethodInfo, ReadOnlyCollection<FilterAttribute>>();
        private static readonly Dictionary<Type, ReadOnlyCollection<FilterAttribute>> typeFilterAttributeCache = 
            new Dictionary<Type, ReadOnlyCollection<FilterAttribute>>();

        public static ICollection<FilterAttribute> GetTypeFilterAttributes(Type type)
        {
            return GetAttributes(typeFilterAttributeCache, type);
        }

        public static ICollection<FilterAttribute> GetMethodFilterAttributes(MethodInfo methodInfo)
        {
            return GetAttributes(methodFilterAttributeCache, methodInfo);
        }

        private static ReadOnlyCollection<TAttribute> GetAttributes<TMemberInfo, TAttribute>(Dictionary<TMemberInfo, ReadOnlyCollection<TAttribute>> lookup, TMemberInfo memberInfo)
            where TAttribute : Attribute
            where TMemberInfo : MemberInfo
        {
            Debug.Assert(memberInfo != null);
            Debug.Assert(lookup != null);

            if (!lookup.ContainsKey(memberInfo))
            {
                lock (lookup)
                {
                    if (!lookup.ContainsKey(memberInfo))
                    {
                        var customAttributes = (TAttribute[]) memberInfo.GetCustomAttributes(typeof (TAttribute), inherit: true);
                        lookup.Add(memberInfo, new ReadOnlyCollection<TAttribute>(customAttributes));
                    }
                }
            }

            return lookup[memberInfo];
        }
    }
}